<?php
class M_qin_relation extends Cemvc_Db_MysqlDb{
  public $PrimaryKey='id';
  /*CEPHP会在要需要时查询主键，但主动设置主键可以使程序执行更快*/

  public function __construct()
  {
    parent::__construct();
  }
  public function get_relation($id, $state=null)
  {
    $wh = '1=1';
    if ($state)
      $wh = "state = '$state'";

    return $this->where(array("user_id = $id or rel_id = $id", $wh))->fetchAll();
  }
  public function get_related_members($id, $state=null)
  {
    $res = $this->get_relation($id, $state=null);
    $a = M_Tools::convert_mysql_results_to_array($res, "user_id", "user_id");
    $b = M_Tools::convert_mysql_results_to_array($res, "rel_id", "user_id");
    $c = array_unique(array_merge(array_keys($a), array_keys($b)));
    sort($c);
    return $c;
  }
  public function get($relation_id)
  {
    return $this->where(array("id = $relation_id"))->fetchOne();
  }
  public function fetch_relation($where)
  {
    return $this->where($where)->fetchAll();
  }
  public function get_mates($user_id, $state = null)
  {
    $db = new M_qin_users();
    $user = $db->get($user_id);
    $field = $user["gender"] == MALE ? "user_id" : "rel_id";
    $rel_field = $user["gender"] == MALE ? "rel_id" : "user_id";
    $wh = '';
    if ($state)
      $wh = "r.state = '$state' and";

    $sql = "SELECT `username`,`realname`,`gender`,`region_code`,`day_of_birth`,`qq_open_id`,`figureurl`,`creator`, r.`state`,$rel_field as id, r.`id` as relation_id FROM `users` u INNER JOIN `relation` r ON u.id = r.$rel_field WHERE $wh u.state = '".RESOURCE_STATE_INIT."' and r.$field = $user_id and r.rel_type = '".WIFE."'";
    return $this->mysqlQuery($sql)->query()->fetchAll();
  }

  public function get_sons($user_id, $state = null)
  {
    $db = new M_qin_users();
    $user = $db->get($user_id);
    $type = $user["gender"] == MALE ? FATHER : MOTHER;
    $wh = '';
    if ($state)
      $wh = "r.state = '$state' and";

    $sql = "SELECT `username`,`realname`,`gender`,`region_code`,`day_of_birth`,`qq_open_id`,`figureurl`,`creator`, r.`state`,`user_id` as id, r.`id` as relation_id FROM `users` u INNER JOIN `relation` r ON r.user_id = u.id WHERE $wh u.state = '".RESOURCE_STATE_INIT."' and r.rel_id = $user_id and r.rel_type = '$type'";
    return $this->mysqlQuery($sql)->query()->fetchAll();
  }

  public function get_mothers($user_id, $state = null)
  {
    $wh = '';
    if ($state)
      $wh = "r.state = '$state' and";

    $sql = "SELECT `username`,`realname`,`gender`,`region_code`,`day_of_birth`,`qq_open_id`,`figureurl`,`creator`, r.`state`,`rel_id` as id, r.`id` as relation_id FROM `users` u INNER JOIN `relation` r ON r.rel_id = u.id WHERE $wh u.state = '".RESOURCE_STATE_INIT."' and r.user_id = $user_id and r.rel_type = '".MOTHER."'";
    
    return $this->mysqlQuery($sql)->query()->fetchAll();
  }
  public function get_fathers($user_id, $state = null)
  {
    $wh = '';
    if ($state)
      $wh = "r.state = '$state' and";

    $sql = "SELECT `username`,`realname`,`gender`,`region_code`,`day_of_birth`,`qq_open_id`,`figureurl`,`creator`, r.`state`,`rel_id` as id, r.`id` as relation_id FROM `users` u INNER JOIN `relation` r ON r.rel_id = u.id WHERE $wh u.state = '".RESOURCE_STATE_INIT."' and r.user_id = $user_id and r.rel_type = '".FATHER."'";
    
    return $this->mysqlQuery($sql)->query()->fetchAll();
  }

  public function clear_cache($id)
  {
    $info = $this->get($id);
    M_Tools::del_cache($this->LastQueryString);

    $read_function = array("get_relation",
			   "get_sons",
			   "get_mates",
			   "get_mothers",
			   "get_fathers",
			   );
      
    foreach($read_function as $func)
      {
	$this->$func($info["user_id"]);
	M_Tools::del_cache($this->LastQueryString);
	$this->$func($info["user_id"], RESOURCE_STATE_INIT);
	M_Tools::del_cache($this->LastQueryString);

	$this->$func($info["rel_id"]);
	M_Tools::del_cache($this->LastQueryString);
	$this->$func($info["rel_id"], RESOURCE_STATE_INIT);
	M_Tools::del_cache($this->LastQueryString);
      }
    
    $history = new M_qin_history();
    $history->get_history_with_content(CONTENT_TYPE_RELATION, $id);
    M_Tools::del_cache($history->LastQueryString);
  }
  public function add($user_id, $rel_id, $type)
  {
    $r = $this->where("user_id = $user_id and rel_id = $rel_id and rel_type = '$type' ")->fetchOne();
    M_Tools::del_cache($this->LastQueryString);

    if (!$r)
      {
	$db = new M_qin_users();
	$user = $db->get($user_id);
	$rel = $db->get($rel_id);

	$res = $this->insert(array("user_id" => $user_id,
				   "user_name" => $user["realname"],
				   "rel_id"  => $rel_id,
				   "rel_name" => $rel["realname"],
				   "rel_type"=> $type));


	/* delete the old cache */
	$this->clear_cache($user_id);
	$this->clear_cache($rel_id);

	$r = $this->get($res["last_insert_id()"]);

	/* add to history */
	$history = new M_qin_history();
	$history->add(array("content_type" => CONTENT_TYPE_RELATION,
			    "content_id"   => $r["id"],
			    "content"      => base64_encode(serialize($r)),
			    "operate_type" => OPERATE_TYPE_ADD,
			    "author_id"    => $_SESSION["id"],
			    "author_name"  => $_SESSION["realname"]));
      }

    return $r;
  }

  public function edit($id, $array)
  {
    $this->where(array("id = $id"))->update($array);

    $this->clear_cache($id);

    $relation = $this->get($id);
    
    /* add to history */
    $history = new M_qin_history();
    $history->add(array("content_type" => CONTENT_TYPE_RELATION,
    			"content_id"   => $id,
    			"content"      => base64_encode(serialize($relation)),
    			"operate_type" => OPERATE_TYPE_EDIT,
    			"author_id"    => $_SESSION["id"],
    			"author_name"  => $_SESSION["realname"]));

    return $relation;    
  }

  public function delete($id)
  {
    /* set to deleted */
    $this->where("id = $id")->update(array("state"=>RESOURCE_STATE_DELETED));

    $this->clear_cache($id);

    $r = $this->get($id);
    /* add to history */
    $history = new M_qin_history();
    $history->add(array("content_type" => CONTENT_TYPE_RELATION,
			"content_id"   => $r["id"],
			"content"      => base64_encode(serialize($r)),
			"operate_type" => OPERATE_TYPE_DELETE,
			"author_id"    => $_SESSION["id"],
			"author_name"  => $_SESSION["realname"]));

    return $r;
  }

  public function restore($relation_id, $history_id)
  {
    /* get history data and set state to init */
    $history = new M_qin_history();
    $res = $history->get($history_id);
    $array = unserialize(base64_decode($res["content"]));
    $array["state"] = RESOURCE_STATE_INIT;
    /* update data */
    $this->where(array("id = $relation_id"))->update($array);

    /* clear cache */
    $this->clear_cache($relation_id);

    /* add to history */
    $relation = $this->get($relation_id);
    $history->add(array("content_type" => CONTENT_TYPE_RELATION,
    			"content_id"   => $relation_id,
    			"content"      => base64_encode(serialize($relation)),
    			"operate_type" => OPERATE_TYPE_RESTORE,
    			"author_id"    => $_SESSION["id"],
    			"author_name"  => $_SESSION["realname"]));

    return $relation;
  }

  public function correct_relation($user, $rel, $type)
  {
    $tb = new M_qin_users();
    $info = $tb->get($user);
    $reverse_relation  = array( SON      =>$info['gender']==MALE ? FATHER : MOTHER, 
				DAUGHTER =>$info['gender']==MALE ? FATHER : MOTHER, 
				HUSBAND  =>WIFE);
    $relation = array(FATHER => FATHER, 
		      MOTHER => MOTHER, 
		      WIFE => WIFE);

    /* there were only three types for relation: father, mother, and wife */
    if (array_key_exists($type, $relation))
      {
	$user_id = $user;
	$rel_id = $rel;
	$rel_type = $type;
      }
    /* if the relation is son/DAUGHTER/HUSBAND, I will reverse the role,  */
    /* and bond them with the basic relationship */
    else if (array_key_exists($type, 
			      $reverse_relation))
      {
	$user_id = $rel;
	$rel_id = $user;
	$rel_type = $reverse_relation[$type];
      }
    else
      die("The relationship you specified is not known.");

    return array("user_id"  => $user_id, 
		 "rel_id"   => $rel_id, 
		 "rel_type" => $rel_type);
  }

  /** 
   * description: get all relatives's ids of users with id in ids
   */
  public function get_relatives_ids($ids)
  {
    $db = new M_qin_relation();
    return $db->setField(array("user_id", "rel_id", "rel_type"))
      ->where(array("(rel_id in (".implode(',',$ids).") and state = '".RESOURCE_STATE_INIT."')or (user_id in (".implode(',',$ids).") and state = '".RESOURCE_STATE_INIT."') "))
      ->fetchAll();
  }
  /**
   * description: get most top user's(may be userid himself or his father or grand father or father's grant father) 
   * id from relatives like an array of 
   * array( array('user_id'=>xx, 'rel_id'=>xx, 'rel_type'=>'xx'),
   *        array('user_id'=>xx, 'rel_id'=>xx, 'rel_type'=>'xx'),
   *        ***
   *      )
   */
  public function get_root_from_relatives($userid, $relatives)
  {
    $root = $userid;
    do
      {
	$root_bk = $root;
	foreach($relatives as $rel)
	  {
	    if ($rel["rel_type"] == FATHER && $rel["user_id"] == $root)
	      {
		$root = $rel["rel_id"];
		break;
	      }
	  }
      }
    while($root != $root_bk);

    return $root;
  }

  /* description: get the family tree  */
  public function get_family_relation($userid)
  {
    $relatives = array($userid);
    $relatives_num = 0;
    $i = 0;
    $members = array($userid);
    do
      {
	/* get user's relative */
	$relatives_num = count($relatives);
	$relatives = $this->get_relatives_ids($members);
	$users = M_Tools::convert_mysql_results_to_array($relatives, "user_id");
	$rels = M_Tools::convert_mysql_results_to_array($relatives, "rel_id");
	
	/* get unique relative, include user it's self */
	$tmp = ($users && $rels) ? array_merge(array_keys($users), array_keys($rels)) : null;
	$members = ($tmp && count($tmp) > count($members)) ? $tmp : $members;
      }
    /* recycle this process for N times */
    while(count($relatives) > $relatives_num && ($i++ < RELATIVE_LEVEL));

    /* get the hightest heritage level user of the relatives */
    $root = $this->get_root_from_relatives($userid, $relatives);

    /* get all relatives' information */
    $user_tbl = new M_qin_users();
    $res = $user_tbl->setField(array("id", "realname", "figureurl", "gender"))->fieldAs("realname as name")->where("id in (".implode(',', $members).")")->fetchAll();
    $members_info = M_Tools::convert_mysql_results_to_array($res, "id");

    /* get the tree */
    return $this->getUserTree($root, $relatives, $members_info);
  }

  /* 
   * $userid:  user id you want to handle
   * $relations, relations resultes from relatinos table;
   * $members_info, user info from users table;
   */
  public function getUserTree($userid, $relations, $members_info)
  {
    $res = array();
    $res["id"] = $userid;
    $res["name"] = urlencode($members_info[$userid]["name"]);
    $res["figureurl"] = file_exists(WEB_ROOT.$members_info[$userid]["figureurl"]) ? $members_info[$userid]["figureurl"] : "";
    $res["gender"] = $members_info[$userid]["gender"];
    foreach($relations as $user)
      {
	/* the user is father's son */
	if ($user["rel_type"] == WIFE)
	  {
	    $mate = array();
	    if ($user['user_id'] == $userid)
	      $mate = $members_info[$user['rel_id']];
	    else if ($user['rel_id'] == $userid)
	      $mate = $members_info[$user['user_id']];
	    
	    if ($mate)
	      {
		if (!isset($res["mates"]))
		  $res["mates"] = array();
		$res["mates"][] = array("id"=>$mate["id"],
					"name"=>urlencode($mate["name"]),
					"figureurl"=>file_exists(WEB_ROOT.$mate["figureurl"]) ? $mate["figureurl"] : "",
					"gender"=>$mate["gender"]);
	      }
	  }
	else if ($user['rel_id'] == $userid && ($user['rel_type'] == FATHER || $user['rel_type'] == MOTHER))
	  {
	    if (!isset($res["children"]))
	      $res["children"] = array();
		
	    $res["children"][] = $this->getUserTree($user['user_id'], $relations, $members_info);
	  }
      }

    /* get all children's mom, she is also my wife */
    foreach($relations as $user)
      {
	if (isset($res["children"]) && is_array($res["children"]) && array_key_exists($user["user_id"], $res["children"]) && $user["rel_type"] == MOTHER)
	  {
	    if (!isset($res["mates"]))
	      $res["mates"] = array();
	    $res["mates"][] = $members_info[$user['rel_id']];
	  }
      }
    return $res;
  }

}
?>
